/*
 * GeneradorPunteros.cpp
 *
 *  Created on: 22/11/2011
 *      Author: putaro
 */

#include "GeneradorPunteros.h"
#include "Codificacion.h"
#include <cmath>
/*
 * Pre: El parámetro es la ruta del directorio donde se guardará al archivo de punteros.
 * Post: Se crea la instancia creando el archivo asociado.
*/
GeneradorPunteros::GeneradorPunteros(const string &rutaDirectorioDestino){
	string rutaCompleta(rutaDirectorioDestino);
	rutaCompleta.append("/");
	rutaCompleta.append(NOMBRE_ARCHIVO_PUNTEROS);
	this -> archivoPunteros.open(rutaCompleta.c_str(), ios::out | ios::binary);
	this -> bufferEscritura = 0;
	this -> contadorBufferEscritura = 0;
	this -> numeroDeBit = 0;
}

/*
 * Pre: La instancia ha sido creada.
 * Post: Se ha destruido la instancia cerrando archivos y grabando el resto de los
 * bits contenidos en el buffer antes de cerrar.
*/
GeneradorPunteros::~GeneradorPunteros() {
	this->cerrarArchivo();
}

/*
 * Post: La instancia ha sido creada y los parámetros son valores no negativos.
 * Post: Se graba en el archivo el par frecuencia - puntero dado por parámetro
 * codificado.
*/
unsigned int GeneradorPunteros::guardarPunteroFrecuencia(const unsigned int puntero ,
												const unsigned int frecuencia){
	unsigned int retorno = this->numeroDeBit;
	Codificacion::codificarDelta(puntero, *this);
	Codificacion::codificarDelta(frecuencia,*this);
	return retorno;
}

/*
 * Pre: La instancia ha sido creada.
 * Post: Se ha cerrado el archivo correctamente grabando el resto del contenido del buffer
 * y completando el buffer si fuese necesario.
 */
void GeneradorPunteros::cerrarArchivo(){
	if( this -> contadorBufferEscritura > 0) {
		this -> archivoPunteros.write(reinterpret_cast<char *>(&this->bufferEscritura),sizeof(int));
	}
	this->archivoPunteros.close();
}

/*
 * Pre: La instancia ha sido creada y el parámetro es 0 o 1.
 * Post: Se ha guardado en el archivo asociado el bit dado por el parámetro.
*/
void GeneradorPunteros::guardarBit(const unsigned int bit){
	if (bit){
		//coloco en buffer
		unsigned int auxiliar = 1;
		auxiliar=(auxiliar<<(sizeof(int)*8 - this -> contadorBufferEscritura-1));
		this -> bufferEscritura = bufferEscritura | (auxiliar);
		this -> contadorBufferEscritura++;
	}else{
		this->contadorBufferEscritura++;
	}
	//si el buffer se lleno guardo en archivo
	if(this->contadorBufferEscritura == (8 * sizeof(unsigned int))){
		this -> archivoPunteros.write(reinterpret_cast<char *>(&this -> bufferEscritura),sizeof(unsigned int));
		this -> contadorBufferEscritura = 0;
		this -> bufferEscritura = 0;
	}
	this -> numeroDeBit += 1;
}

/*
 * Pre: La instancia ha sido creada, y el entero pasado por parámetro es positivo.
 * Post: Se ha guardado el entero pasado por parámetro en el archivo asociado a la
 * instancia.
*/
void GeneradorPunteros::guardarEntero(const unsigned int valor){
	if(this->contadorBufferEscritura == 0) {
		unsigned int auxiliar = valor;
		this -> archivoPunteros.write(reinterpret_cast<char *>(&auxiliar),sizeof(unsigned int));
	} else {
		//lleno el buffer
		unsigned int auxiliar = 0;
		auxiliar = valor >> this -> contadorBufferEscritura;
		this -> bufferEscritura = bufferEscritura | auxiliar;
		//grabo lo que entro en el buffer
		this -> archivoPunteros.write(reinterpret_cast<char *>(&(this->bufferEscritura)),sizeof(unsigned int));
		//actualizo el buffer
		bufferEscritura = valor <<(8 * sizeof(unsigned int) - this->contadorBufferEscritura);
	}
	this -> numeroDeBit += sizeof(unsigned int) * 8;
}
